home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Blender 2.49b / blender-2.49b-windows.exe / $_4_ / .blender / scripts / bevel_center.py < prev    next >
Text File  |  2009-08-31  |  13KB  |  475 lines

  1. #!BPY
  2. # -*- coding: utf-8 -*-
  3. """ Registration info for Blender menus
  4. Name: 'Bevel Center'
  5. Blender: 243
  6. Group: 'Mesh'
  7. Tip: 'Bevel selected faces, edges, and vertices'
  8. """
  9.  
  10. __author__ = "Loic BERTHE"
  11. __url__ = ("blender", "blenderartists.org")
  12. __version__ = "2.0"
  13.  
  14. __bpydoc__ = """\
  15. This script implements vertex and edges bevelling in Blender.
  16.  
  17. Usage:
  18.  
  19. Select the mesh you want to work on, enter Edit Mode and select the edges
  20. to bevel.  Then run this script from the 3d View's Mesh->Scripts menu.
  21.  
  22. You can control the thickness of the bevel with the slider -- redefine the
  23. end points for bigger or smaller ranges.  The thickness can be changed even
  24. after applying the bevel, as many times as needed.
  25.  
  26. For an extra smoothing after or instead of direct bevel, set the level of
  27. recursiveness and use the "Recursive" button. 
  28.  
  29. This "Recursive" Button, won't work in face select mode, unless you choose
  30. "faces" in the select mode menu.
  31.  
  32. Notes:<br>
  33.     You can undo and redo your steps just like with normal mesh operations in
  34. Blender.
  35. """
  36.  
  37. ######################################################################
  38. # Bevel Center v2.0 for Blender
  39.  
  40. # This script lets you bevel the selected vertices or edges and control the
  41. # thickness of the bevel
  42.  
  43. # (c) 2004-2006 Lo├»c Berthe (loic+blender@lilotux.net)
  44. # released under Blender Artistic License
  45.  
  46. ######################################################################
  47.  
  48. import Blender
  49. from Blender import NMesh, Window, Scene
  50. from Blender.Draw import *
  51. from Blender.Mathutils import *
  52. from Blender.BGL import *
  53. import BPyMessages
  54. #PY23 NO SETS#
  55. '''
  56. try:
  57.     set()
  58. except:
  59.     from sets import set    
  60. '''
  61.  
  62. ######################################################################
  63. # Functions to handle the global structures of the script NF, NE and NC
  64. # which contain informations about faces and corners to be created
  65.  
  66. global E_selected
  67. E_selected = NMesh.EdgeFlags['SELECT']
  68.  
  69. old_dist = None
  70.  
  71. def act_mesh_ob():
  72.     scn = Scene.GetCurrent()
  73.     ob = scn.objects.active
  74.     if ob == None or ob.type != 'Mesh': 
  75.         BPyMessages.Error_NoMeshActive()
  76.         return
  77.     
  78.     if ob.getData(mesh=1).multires:
  79.         BPyMessages.Error_NoMeshMultiresEdit()
  80.         return
  81.     
  82.     return ob
  83.  
  84. def make_sel_vert(*co):
  85.     v= NMesh.Vert(*co)
  86.     v.sel = 1
  87.     me.verts.append(v)
  88.     return v
  89.  
  90. def make_sel_face(verts):
  91.     f = NMesh.Face(verts)
  92.     f.sel = 1
  93.     me.addFace(f)
  94.  
  95. def add_to_NV(old,dir,new):
  96.     try:
  97.         NV[old][dir] = new
  98.     except:
  99.         NV[old] = {dir:new}       
  100.  
  101. def get_v(old, *neighbors):
  102.     # compute the direction of the new vert
  103.     if len(neighbors) == 1: dir = (neighbors[0].co - old.co).normalize()
  104.         #dir
  105.     else: dir = (neighbors[0].co - old.co).normalize() + (neighbors[1].co-old.co).normalize()
  106.      
  107.     # look in NV if this vert already exists
  108.     key = tuple(dir)
  109.     if old in NV and key in NV[old] : return NV[old][key]
  110.     
  111.     # else, create it 
  112.     new = old.co + dist.val*dir
  113.     v = make_sel_vert(new.x,new.y,new.z)
  114.     add_to_NV(old,key,v)
  115.     return v
  116.  
  117. def make_faces():
  118.     """ Analyse the mesh, make the faces corresponding to selected faces and
  119.     fill the structures NE and NC """
  120.  
  121.     # make the differents flags consistent
  122.     for e in me.edges:
  123.         if e.flag & E_selected :
  124.             e.v1.sel = 1
  125.             e.v2.sel = 1
  126.     
  127.     NF =[]              # NF : New faces
  128.     for f in me.faces:
  129.         V = f.v
  130.         nV = len(V)
  131.         enumV = range(nV)
  132.         E = [me.findEdge(V[i],V[(i+1) % nV]) for i in enumV]
  133.         Esel = [x.flag & E_selected for x in E]
  134.         
  135.         # look for selected vertices and creates a list containing the new vertices
  136.         newV = V[:] 
  137.         changes = False
  138.         for (i,v) in enumerate(V):
  139.             if v.sel :
  140.                 changes = True
  141.                 if   Esel[i-1] == 0 and Esel[i] == 1 :  newV[i] = get_v(v,V[i-1])
  142.                 elif Esel[i-1] == 1 and Esel[i] == 0 :  newV[i] = get_v(v,V[(i+1) % nV])
  143.                 elif Esel[i-1] == 1 and Esel[i] == 1 :  newV[i] = get_v(v,V[i-1],V[(i+1) % nV])
  144.                 else :                                  newV[i] = [get_v(v,V[i-1]),get_v(v,V[(i+1) % nV])]
  145.         
  146.         if changes:
  147.             # determine and store the face to be created
  148.  
  149.             lenV = [len(x) for x in newV]
  150.             if 2 not in lenV :              
  151.                 new_f = NMesh.Face(newV)
  152.                 if sum(Esel) == nV : new_f.sel = 1
  153.                 NF.append(new_f)
  154.                 
  155.             else :
  156.                 nb2 = lenV.count(2)
  157.                 
  158.                 if nV == 4 :                # f is a quad
  159.                     if nb2 == 1 :
  160.                         ind2 = lenV.index(2)
  161.                         NF.append(NMesh.Face([newV[ind2-1],newV[ind2][0],newV[ind2][1],newV[ind2-3]]))
  162.                         NF.append(NMesh.Face([newV[ind2-1],newV[ind2-2],newV[ind2-3]]))
  163.                     
  164.                     elif nb2 == 2 :
  165.                         # We must know if the tuples are neighbours
  166.                         ind2 = ''.join([str(x) for x in lenV+lenV[:1]]).find('22')
  167.                         
  168.                         if ind2 != -1 :     # They are 
  169.                             NF.append(NMesh.Face([newV[ind2][0],newV[ind2][1],newV[ind2-3][0],newV[ind2-3][1]]))
  170.                             NF.append(NMesh.Face([newV[ind2][0],newV[ind2-1],newV[ind2-2],newV[ind2-3][1]]))
  171.                         
  172.                         else:               # They aren't
  173.                             ind2 = lenV.index(2)
  174.                             NF.append(NMesh.Face([newV[ind2][0],newV[ind2][1],newV[ind2-2][0],newV[ind2-2][1]]))
  175.                             NF.append(NMesh.Face([newV[ind2][1],newV[ind2-3],newV[ind2-2][0]]))
  176.                             NF.append(NMesh.Face([newV[ind2][0],newV[ind2-1],newV[ind2-2][1]]))
  177.                     
  178.                     elif nb2 == 3 :
  179.                         ind2 = lenV.index(3)
  180.                         NF.append(NMesh.Face([newV[ind2-1][1],newV[ind2],newV[ind2-3][0]]))
  181.                         NF.append(NMesh.Face([newV[ind2-1][0],newV[ind2-1][1],newV[ind2-3][0],newV[ind2-3][1]]))
  182.                         NF.append(NMesh.Face([newV[ind2-3][1],newV[ind2-2][0],newV[ind2-2][1],newV[ind2-1][0]]))
  183.                     
  184.                     else:
  185.                         if    (newV[0][1].co-newV[3][0].co).length + (newV[1][0].co-newV[2][1].co).length \
  186.                             < (newV[0][0].co-newV[1][1].co).length + (newV[2][0].co-newV[3][1].co).length :
  187.                             ind2 = 0
  188.                         else :
  189.                             ind2 = 1
  190.                         NF.append(NMesh.Face([newV[ind2-1][0],newV[ind2-1][1],newV[ind2][0],newV[ind2][1]]))
  191.                         NF.append(NMesh.Face([newV[ind2][1],newV[ind2-3][0],newV[ind2-2][1],newV[ind2-1][0]]))
  192.                         NF.append(NMesh.Face([newV[ind2-3][0],newV[ind2-3][1],newV[ind2-2][0],newV[ind2-2][1]]))
  193.                 
  194.                 else :                      # f is a tri
  195.                     if nb2 == 1:
  196.                         ind2 = lenV.index(2)
  197.                         NF.append(NMesh.Face([newV[ind2-2],newV[ind2-1],newV[ind2][0],newV[ind2][1]]))
  198.                     
  199.                     elif nb2 == 2:
  200.                         ind2 = lenV.index(3)
  201.                         NF.append(NMesh.Face([newV[ind2-1][1],newV[ind2],newV[ind2-2][0]]))
  202.                         NF.append(NMesh.Face([newV[ind2-2][0],newV[ind2-2][1],newV[ind2-1][0],newV[ind2-1][1]]))
  203.                     
  204.                     else:
  205.                         ind2 = min( [((newV[i][1].co-newV[i-1][0].co).length, i) for i in enumV] )[1]
  206.                         NF.append(NMesh.Face([newV[ind2-1][1],newV[ind2][0],newV[ind2][1],newV[ind2-2][0]]))
  207.                         NF.append(NMesh.Face([newV[ind2-2][0],newV[ind2-2][1],newV[ind2-1][0],newV[ind2-1][1]]))
  208.                 
  209.                 # Preparing the corners
  210.                 for i in enumV:
  211.                     if lenV[i] == 2 :       NC.setdefault(V[i],[]).append(newV[i])
  212.                 
  213.             
  214.             old_faces.append(f)
  215.             
  216.             # Preparing the Edges
  217.             for i in enumV:
  218.                 if Esel[i]:
  219.                     verts = [newV[i],newV[(i+1) % nV]]
  220.                     if V[i].index > V[(i+1) % nV].index : verts.reverse()
  221.                     NE.setdefault(E[i],[]).append(verts)
  222.     
  223.     # Create the faces
  224.     for f in NF: me.addFace(f)
  225.  
  226. def make_edges():
  227.     """ Make the faces corresponding to selected edges """
  228.  
  229.     for old,new in NE.iteritems() :
  230.         if len(new) == 1 :                      # This edge was on a border 
  231.             oldv = [old.v1, old.v2]
  232.             if old.v1.index < old.v2.index : oldv.reverse()
  233.             
  234.             make_sel_face(oldv+new[0])
  235.  
  236.             me.findEdge(*oldv).flag   |= E_selected
  237.             me.findEdge(*new[0]).flag |= E_selected
  238.  
  239.             #PY23 NO SETS# for v in oldv : NV_ext.add(v)
  240.             for v in oldv : NV_ext[v]= None
  241.         
  242.         else:
  243.             make_sel_face(new[0] + new[1][::-1])
  244.  
  245.             me.findEdge(*new[0]).flag |= E_selected
  246.             me.findEdge(*new[1]).flag |= E_selected
  247.  
  248. def make_corners():
  249.     """ Make the faces corresponding to corners """
  250.  
  251.     for v in NV.iterkeys():
  252.         V = NV[v].values()
  253.         nV = len(V)
  254.         
  255.         if nV == 1:     pass
  256.         
  257.         elif nV == 2 :
  258.             #PY23 NO SETS# if v in NV_ext:
  259.             if v in NV_ext.iterkeys():
  260.                 make_sel_face(V+[v])
  261.                 me.findEdge(*V).flag   |= E_selected
  262.                 
  263.         else:
  264.             #PY23 NO SETS# if nV == 3 and v not in NV_ext : make_sel_face(V)
  265.             if nV == 3 and v not in NV_ext.iterkeys() : make_sel_face(V)
  266.             
  267.             
  268.             else :
  269.                 
  270.                 # We need to know which are the edges around the corner.
  271.                 # First, we look for the quads surrounding the corner.
  272.                 eed = []
  273.                 for old, new in NE.iteritems():
  274.                     if v in (old.v1,old.v2) :
  275.                         if v.index == min(old.v1.index,old.v2.index) :   ind = 0
  276.                         else                                         :   ind = 1
  277.                         
  278.                         if len(new) == 1:       eed.append([v,new[0][ind]])
  279.                         else :                  eed.append([new[0][ind],new[1][ind]])
  280.                 
  281.                 # We will add the edges coming from faces where only one vertice is selected.
  282.                 # They are stored in NC.
  283.                 if v in NC:                     eed = eed+NC[v]
  284.  
  285.                 # Now we have to sort these vertices
  286.                 hc = {}
  287.                 for (a,b) in eed :
  288.                     hc.setdefault(a,[]).append(b)
  289.                     hc.setdefault(b,[]).append(a)
  290.                 
  291.                 for x0,edges in hc.iteritems():
  292.                     if len(edges) == 1 :        break
  293.                 
  294.                 b = [x0]                        # b will contain the sorted list of vertices
  295.                 
  296.                 for i in xrange(len(hc)-1):
  297.                     for x in hc[x0] :
  298.                         if x not in b :         break
  299.                     b.append(x)
  300.                     x0 = x
  301.  
  302.                 b.append(b[0])
  303.  
  304.                 # Now we can create the faces
  305.                 if len(b) == 5:                 make_sel_face(b[:4])
  306.  
  307.                 else:
  308.                     New_V = Vector(0.0, 0.0,0.0)
  309.                     New_d = [0.0, 0.0,0.0]
  310.         
  311.                     for x in hc.iterkeys():         New_V += x.co
  312.                     for dir in NV[v] :
  313.                         for i in xrange(3):     New_d[i] += dir[i]
  314.  
  315.                     New_V *= 1./len(hc)
  316.                     for i in xrange(3) :         New_d[i] /= nV
  317.                     
  318.                     center = make_sel_vert(New_V.x,New_V.y,New_V.z)
  319.                     add_to_NV(v,tuple(New_d),center)
  320.  
  321.                     for k in xrange(len(b)-1):   make_sel_face([center, b[k], b[k+1]])
  322.                 
  323.         if  2 < nV and v in NC :
  324.             for edge in NC[v] :                 me.findEdge(*edge).flag   |= E_selected
  325.  
  326. def clear_old():
  327.     """ Erase old faces and vertices """
  328.  
  329.     for f in old_faces: me.removeFace(f)
  330.     
  331.     for v in NV.iterkeys():
  332.         #PY23 NO SETS# if v not in NV_ext :  me.verts.remove(v)
  333.         if v not in NV_ext.iterkeys() :  me.verts.remove(v)
  334.  
  335.     for e in me.edges:
  336.         if e.flag & E_selected :
  337.             e.v1.sel = 1
  338.             e.v2.sel = 1
  339.     
  340.  
  341. ######################################################################
  342. # Interface
  343.  
  344. global dist
  345.     
  346. dist = Create(0.2)
  347. left = Create(0.0)
  348. right = Create(1.0)
  349. num = Create(2)
  350.  
  351. # Events
  352. EVENT_NOEVENT = 1
  353. EVENT_BEVEL = 2
  354. EVENT_UPDATE = 3
  355. EVENT_RECURS = 4
  356. EVENT_EXIT = 5
  357.  
  358. def draw():
  359.     global dist, left, right, num, old_dist
  360.     global EVENT_NOEVENT, EVENT_BEVEL, EVENT_UPDATE, EVENT_RECURS, EVENT_EXIT
  361.  
  362.     glClear(GL_COLOR_BUFFER_BIT)
  363.     Button("Bevel",EVENT_BEVEL,10,100,280,25)
  364.     
  365.     BeginAlign()
  366.     left=Number('',  EVENT_NOEVENT,10,70,45, 20,left.val,0,right.val,'Set the minimum of the slider')
  367.     dist=Slider("Thickness  ",EVENT_UPDATE,60,70,180,20,dist.val,left.val,right.val,0, \
  368.             "Thickness of the bevel, can be changed even after bevelling")
  369.     right = Number("",EVENT_NOEVENT,245,70,45,20,right.val,left.val,200,"Set the maximum of the slider")
  370.  
  371.     EndAlign()
  372.     glRasterPos2d(8,40)
  373.     Text('To finish, you can use recursive bevel to smooth it')
  374.     
  375.     
  376.     if old_dist != None:
  377.         num=Number('',  EVENT_NOEVENT,10,10,40, 16,num.val,1,100,'Recursion level')
  378.         Button("Recursive",EVENT_RECURS,55,10,100,16)
  379.     
  380.     Button("Exit",EVENT_EXIT,210,10,80,20)
  381.  
  382. def event(evt, val):
  383.     if ((evt == QKEY or evt == ESCKEY) and not val): Exit()
  384.  
  385. def bevent(evt):
  386.     if evt == EVENT_EXIT        : Exit()
  387.     elif evt == EVENT_BEVEL     : bevel()
  388.     elif evt == EVENT_UPDATE    :
  389.         try: bevel_update()
  390.         except NameError        : pass
  391.     elif evt == EVENT_RECURS    : recursive()
  392.  
  393. Register(draw, event, bevent)
  394.  
  395. ######################################################################
  396. def bevel():
  397.     """ The main function, which creates the bevel """
  398.     global me,NV,NV_ext,NE,NC, old_faces,old_dist
  399.     
  400.     ob = act_mesh_ob()
  401.     if not ob: return
  402.     
  403.     Window.WaitCursor(1) # Change the Cursor
  404.     t= Blender.sys.time()
  405.     is_editmode = Window.EditMode() 
  406.     if is_editmode: Window.EditMode(0)
  407.     
  408.     me = ob.data
  409.  
  410.     NV = {}
  411.     #PY23 NO SETS# NV_ext = set()
  412.     NV_ext= {}
  413.     NE = {}
  414.     NC = {}
  415.     old_faces = []
  416.  
  417.     make_faces()
  418.     make_edges()
  419.     make_corners()
  420.     clear_old()
  421.  
  422.     old_dist = dist.val
  423.     print '\tbevel in %.6f sec' % (Blender.sys.time()-t)
  424.     me.update(1)
  425.     if is_editmode: Window.EditMode(1)
  426.     Window.WaitCursor(0)
  427.     Blender.Redraw()
  428.  
  429. def bevel_update():
  430.     """ Use NV to update the bevel """
  431.     global dist, old_dist
  432.     
  433.     if old_dist == None:
  434.         # PupMenu('Error%t|Must bevel first.')
  435.         return
  436.     
  437.     is_editmode = Window.EditMode()
  438.     if is_editmode: Window.EditMode(0)
  439.     
  440.     fac = dist.val - old_dist
  441.     old_dist = dist.val
  442.  
  443.     for old_v in NV.iterkeys():
  444.         for dir in NV[old_v].iterkeys():
  445.             for i in xrange(3):
  446.                 NV[old_v][dir].co[i] += fac*dir[i]
  447.  
  448.     me.update(1)
  449.     if is_editmode: Window.EditMode(1)
  450.     Blender.Redraw()
  451.  
  452. def recursive():
  453.     """ Make a recursive bevel... still experimental """
  454.     global dist
  455.     from math import pi, sin
  456.     
  457.     if num.val > 1:
  458.         a = pi/4
  459.         ang = []
  460.         for k in xrange(num.val):
  461.             ang.append(a)
  462.             a = (pi+2*a)/4
  463.  
  464.         l = [2*(1-sin(x))/sin(2*x) for x in ang]
  465.         R = dist.val/sum(l)
  466.         l = [x*R for x in l]
  467.  
  468.         dist.val = l[0]
  469.         bevel_update()
  470.  
  471.         for x in l[1:]:
  472.             dist.val = x
  473.             bevel()
  474.  
  475.